	/************************************************************************************************
	 	
		Factory:	jsl.Function
													
		Methods:
			f				Function			(f)		- sid: 2.0
			f				augment				(f..)	- sid: 2.0
			a				getParameters	()		- sid: 2.0
			s				getSignature	()		- sid: 2.0		
			body		getBody				()		- sid: 2.0
			b				isSubTypeOf		(f)		- sid: 2.0
			b				isSuperTypeOf	(f)		- sid: 2.0
			
		Overriding:
			name		getName				()		- sid: 2.0
		
		Function to string conversions:			
			@sys: Safari 4.0.4 		- Leaves comments, but only into the function body not in the function signature
			@sys: Explorer 8 			- Leaves all comments, leaves the instructions without the semicolon, retains also
															the comments out the function in the same line (ex: function(){}/ *}* /) 
			@sys: Firefox 3.6.12 	- add semicolon after the instructions
			@sys: Opera 10.63 		- putting comments or \n  between the function signature is not recommended, it generates a bug
															when the function is converted into text: the keyword function is omitted (in some cases on eval)

			
		Regular expressions:
			@sys: Firefox 3.6/ 		 
						Chrome 4.024 		- put a re literal in the code generates ever the same object at every 
															execution passage, (not a new re object), re.lastIndex retains the last value and is not 
															set to zero. If we add a property to the re object the property exists at every execution 
															of the line of code.
			@sys: Explorer 8 			- if a group of the re not match, it is set to '' not a null in the array
															ex: ['hdd', '', ''] not ['hdd', null, null] -> !v[3] not v[3] != null
		
		Function objects:			
			@sys: Chrome 4.024 		- name is a readonly property of the function object
			@sys: Firefox 3.6.3 	- name is a writable property of the function object
						
	************************************************************************************************/
	
	//-------------------------------------------------------------------------------
	jsl.Function = function(f) {
		try {
	   	var proto, rv
    	//@d[
      if(arguments.length > 1) throw jsl.ParamError()//@d]
			
			if(arguments.length) {		
				//@d[
				jsl.validate(f, "f")//@d]
				if(f.__augmented)	return f
				else							rv = f				
			}
			else
				rv = new Function
															
			proto = jsl.Function.prototype
			
    	for(var id in proto)
    		if(proto.hasOwnProperty(id))
					rv[id] = proto[id]
				
			rv.__native = arguments.callee.__native			
    	return rv	    			
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.__name 		= "jsl.Function"
	//-------------------------------------------------------------------------------
	jsl.Function.prototype 	= jsl.Object()	
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.augment = function() {
		try {
			var fs, len, proto, id
			//@d[
     	if(!jsl.isFunction(this))	throw jsl.TypeError("BadMethodCall:Function")			
			if(!arguments.length)			throw jsl.ParamError()//@d]
			
			fs 	= arguments
			len	= fs.length
			
			for(var a = 0; a < len; a++) {
				//@d[
				jsl.validate(fs[a], "f", "f[" + a + "]")//@d]
				proto = fs[a].prototype

				for(id in proto)
					if(proto.hasOwnProperty(id) && jsl.isFunction(proto[id]))
						this.prototype[id] = proto[id]			
			}
								
			return this
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.getParameters = function() {
		try {
			var txt
			//@d[
     	if(!jsl.isFunction(this))	throw jsl.TypeError("BadMethodCall:Function")						
			if(arguments.length)			throw jsl.ParamError()//@d]
			
			//very slow -> caching
			if(!this.__params) {
				txt						= this + ""			
				txt 					= txt.replace(/\/\*(?:[\s\S])*?\*\//g, "") 
				txt 					= txt.replace(/\/\/.*\n/g, "")						
				txt 					= txt.replace(/[\n\s]+/g, "")
				//@sys: Explorer v.8 - args.callee + "" - > wrap the function into round brackets (function() {...})			
				txt 					= txt.match(/[\s\S]*?function[^(]*\(([^\)]*)\)/)[1]			
				this.__params	= txt.length ? txt.split(",") : []		
			}			
				
			return this.__params.slice()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)		
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.getSignature = function() {
		try {//@d[
     	if(!jsl.isFunction(this))	throw jsl.TypeError("BadMethodCall:Function")					
			if(arguments.length)			throw jsl.ParamError()//@d]
			
			return jsl.Function.getName(this) + "(" + jsl.Function.getParameters(this).join(",") + ")" 
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.getBody = function() {
		try {
			var txt, idx, idx2
			//@d[
     	if(!jsl.isFunction(this))	throw jsl.TypeError("BadMethodCall:Function")						
			if(arguments.length)			throw jsl.ParamError()//@d]
												
			//very slow -> caching
			//@sys: Chrome 9/Opera 10.63 - when a function is converted into string, his content can be altered. Some \n
			//			can be deleted and can occour -> function() { ;;//txt } with a inline comment without \n terminator
			if(!this.__body) {				
				txt					= this + ""			
				txt 				= txt.replace(/\/\*[\s\S]*?\*\//g, "") 
				txt 				= txt.replace(/\/\/[^\n]*/g, "")						
				
				//@sys: Konqueror windows 4.4.0 kde(4.4.0) - function(){} + "" = function anonymous(); 						
				//			A lot of borowsers oddities when a function is converted into text. If we don't find
				//			the indexes we consider the body empty
				idx					= txt.indexOf("{")
				idx2				= txt.lastIndexOf("}")				
				this.__body	= idx !== -1 && idx2 !== -1 ? txt.slice(idx + 1, idx2) : ""				
			}
			
			return this.__body
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.getName = function() {
		try {
			var txt
			//@d[
     	if(!jsl.isFunction(this))	throw jsl.TypeError("BadMethodCall:Function")						
			if(arguments.length)			throw jsl.ParamError()//@d]
      			
			if(!this.__name) {
				txt					= this + ""			
				txt 				= txt.replace(/\/\*(?:[\s\S])*?\*\//g, "") 
				txt 				= txt.replace(/\/\/.*\n/g, "")						
				txt 				= txt.replace(/[\n\s]+/g, "")
				
				this.__name	= txt.match(/[\s\S]*?function([^(]*)/)[1] || "anonymous"
			}			
			return this.__name  
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.isSubTypeOf = function(f) {
		try {//@d[
      if(!jsl.isFunction(this))		throw jsl.TypeError("BadMethodCall:Function")
			if(arguments.length !== 1)	throw jsl.ParamError()			
			jsl.validate(f, "f", "f")//@d]
			
			return f.prototype.isPrototypeOf(this.prototype)
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	//-------------------------------------------------------------------------------
	jsl.Function.prototype.isSuperTypeOf = function(f) {
		try {//@d[
      if(!jsl.isFunction(this))		throw jsl.TypeError("BadMethodCall:Function")
			if(arguments.length !== 1)	throw jsl.ParamError()			
			jsl.validate(f, "f", "f")//@d]
			
			return this.prototype.isPrototypeOf(f.prototype)
		}
		catch(e) {
  		jsl.throwError(e, this, arguments)
		}
	}
	
	//Function init
	//-------------------------------------------------------------------------------
	;(function() {
		
		var proto 
		
		jsl.Function.__native	= jsl.Object.__native.copy().merge(jsl.Function.prototype)
		proto									= jsl.Function.__native
	
		//Overriding not enumerables in the merge
		//-------------------------------------------------------------------------------
		proto.getName		= jsl.Function.prototype.getName		
		
		//Data
		//-------------------------------------------------------------------------------
		proto.__params	= null
		proto.__body 		= undefined
		proto						= jsl.Function.prototype
				
		for(var id in proto) 
			if(proto.hasOwnProperty(id)) 
				if(id.charAt(0) !== "_" && jsl.isFunction(proto[id]) && !proto[id].__name) {
					
					jsl.Function[id] = function(obj) { 
						try {//@d[
							if(!arguments.length)	throw jsl.ParamError() 
							if(obj === null)			throw jsl.ParamError("NullValue:obj")//@d]
							
							return arguments.callee.__f.apply(obj, Array.prototype.slice.call(arguments, 1)) 
						}
						catch(e) {
							jsl.throwError(e, this, arguments)
						}
					}
					
					jsl.Function[id].__name	= id
					jsl.Function[id].__f		= proto[id]				
					proto[id].__name 				= id
				}			
	})()
